﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using Autofac.Core.Lifetime;

namespace Autofac.Engine
{
    public partial class EngineContext
    {
        #region Fields
        private static Func<IContainer, ILifetimeScope> _scope;
        private static IContainer _container;

        public static ILifetimeScope Scope
        {
            get
            {
                return _scope.Invoke(_container);
            }
        }
        #endregion

        #region Utilities
        protected static void RegisterDependencies()
        {
            var builder = new ContainerBuilder();
            var container = builder.Build();

            var typeFinder = new AppDomainTypeFinder();
            builder = new ContainerBuilder();
            builder.RegisterInstance(typeFinder).As<ITypeFinder>().SingleInstance();
            builder.Update(container);

            builder = new ContainerBuilder();
            var drTypes = typeFinder.FindClassesOfType<IDependencyRegistrar>();
            var drInstances = new List<IDependencyRegistrar>();
            foreach (var drType in drTypes)
                drInstances.Add((IDependencyRegistrar)Activator.CreateInstance(drType));

            drInstances = drInstances.AsQueryable().OrderBy(t => t.Order).ToList();
            foreach (var dependencyRegistrar in drInstances)
                dependencyRegistrar.Register(builder, typeFinder);
            builder.Update(container);

            _container = container;
        }
        protected static ILifetimeScope DefaultScope(IContainer container)
        {
            return container;
        }
        protected static void SetScope(ScopeTag tag)
        {
            switch (tag)
            {
                case ScopeTag.Http:
                    _scope = (e) => { return e.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag); };
                    break;
                default:
                    _scope = DefaultScope;
                    break;
            }
        }
        #endregion

        #region Methods
        [MethodImpl(MethodImplOptions.Synchronized)]
        public static IContainer Initialize(bool forceRecreate, ScopeTag tag = ScopeTag.None)
        {
            if (_container == null || forceRecreate)
            {
                RegisterDependencies();
            }
            SetScope(tag);
            return _container;
        }
        public static void Replace(IContainer container, ScopeTag tag = ScopeTag.None)
        {
            SetScope(tag);
            _container = container;
        }
        #endregion
    }
}
